/*
 * Consumer.java
 *
 * Created on October 20, 2007, 6:52 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package simulationengine.process;

//import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import simulationengine.animation.AnimationCommand;

/**
 *
 * @author jkeister
 */
public class Consumer extends Thread {
    
     AtomicInteger time;
     
	//LinkedBlockingQueue<AnimationCommand> commands;
        PriorityBlockingQueue<AnimationCommand> commands;
	
     //Reset on second resource?
     int startTime = 0;
     int serviceTime = 0;
     int waitTime = 0;
     int completionTime = 0;
     
     //Persistent across resources
     int inServiceTime = 0;
     int inWaitTime = 0;
     final int endTime;
     final int idNumber;
     
     
     Resource useThis;
     Resource prevR;
     Resource nextR;
     
     final boolean DEBUG = true;
    
    /** Creates a new instance of Consumer */
    public Consumer(int endSimulation, int bornOnDate, Resource resource, int id, PriorityBlockingQueue<AnimationCommand> commands) 
    {
        endTime = endSimulation;
        
        startTime = bornOnDate;
        
        useThis = resource;
        
        idNumber = id;
	   
	   this.commands = commands;
    }
        
    public int getTime()
    {
        return time.intValue();
    }
    
    public void run()
    {
	
        //System.out.println("Consumer do");
        do
        {
            //Try to acquire resource
            try{ useThis.available.acquire(); }
                catch(InterruptedException e) 
                    {System.out.println("Interrupted");}

            if(useThis.localTime.intValue() < endTime)
            {
                if(useThis.nextAvailableResourceQ == null)
                {
commands.put(new AnimationCommand(AnimationCommand.Command.ADD, startTime, idNumber, 0, useThis.type));
                    if(DEBUG)
                        System.out.println(startTime);
                    waitTime = useThis.localTime.intValue()-startTime;
                    if(0 > waitTime)
                        waitTime = 0;
                    if(DEBUG)
                        System.out.println("\t"+waitTime);
                    inWaitTime += waitTime;
commands.add(new AnimationCommand(AnimationCommand.Command.BEGIN_SERVICE, useThis.localTime.intValue()+waitTime, idNumber, 0, useThis.type));
                    serviceTime = useThis.service();
                    inServiceTime += serviceTime;
                    if(DEBUG)
                        System.out.println("\t\t"+serviceTime);

                    completionTime = serviceTime + waitTime + startTime;
                    useThis.localTime.set(completionTime);
commands.add(new AnimationCommand(AnimationCommand.Command.END_SERVICE, useThis.localTime.intValue(), idNumber, 0, useThis.type));
                }
                else
                {
                    Resource nowR = null;
                    try{ nowR = (Resource)useThis.nextAvailableResourceQ.take(); }
                        catch(InterruptedException e) 
                            {System.out.println("Interrupted trying nowR");}

                    if(nowR != null)
                    {
commands.put(new AnimationCommand(AnimationCommand.Command.ADD, startTime, idNumber, 0, nowR.type));
                            if(DEBUG)
                                System.out.println(startTime);
                            
                        waitTime = nowR.localTime.intValue()-startTime;
                        if(0 > waitTime || useThis.noDelay)
                            waitTime = 0;
                        if(DEBUG)
                            System.out.println("\t"+waitTime);
                        inWaitTime += waitTime;
commands.add(new AnimationCommand(AnimationCommand.Command.BEGIN_SERVICE, useThis.localTime.intValue()+waitTime, idNumber, 0, nowR.type));
                        
                        serviceTime = nowR.service();
                        inServiceTime += serviceTime;

                        completionTime = serviceTime + waitTime + startTime;
                        nowR.localTime.set(completionTime);
                        if(DEBUG)
                            System.out.println("\t\t"+serviceTime);

                        //if using a serializing resource
                        if(useThis.syncExit)
                            //Only move on to next resource if the current thread is the lowest time at the cyclicBarrier
                            while(completionTime != useThis.lowest.intValue() && completionTime <= endTime && useThis.localTime.get() < endTime)
                                useThis.record(completionTime);
                        
commands.add(new AnimationCommand(AnimationCommand.Command.END_SERVICE, useThis.localTime.intValue(), idNumber, 0, nowR.type));
                        useThis.nextAvailableResourceQ.put(nowR);
                        if(useThis.localTime.get() > endTime)
                        {
                            useThis.nextResource = null;
                            System.out.println("Internal expiration");
                            return;
                        }
                    }
                    else
                        System.out.println("nowR = null");
                }

                //if there's a nextResource, acquire it, but don't block anymore?
                nextR = useThis.nextResource;

                //Release resource
                if(nextR == null)
                {
                    useThis.available.release();
                    useThis = null;
                }
                else
                {
                        prevR = useThis;
                        useThis = nextR;
                        prevR.available.release();
                }
                if(DEBUG)
                    System.out.println("\t\t\t" + completionTime);
                startTime = completionTime;
                //completionTime = 0;
                
            }
            else
            {
                if(startTime < endTime+25)
                    System.out.println("Expired"+startTime);
                useThis.available.release();
                useThis = null;
            }
        }while(useThis != null && completionTime < endTime);
    }
}